package sessions;

import java.sql.Date;
import java.util.LinkedList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import entities.Admin;
import entities.Has;
import entities.Skill;
import entities.User;
import exceptions.AdminAuthenticationException;
import exceptions.AuthenticationException;
import exceptions.DuplicatedUsernameException;

/**
 * Session Bean implementation class UserManager
 */
@Stateless
public class UserManager implements UserManagerRemote, UserManagerLocal {

	@PersistenceContext(unitName = "SWIMv2")
	private EntityManager em;

	/**
	 * Default constructor.
	 */
	public UserManager() {
		// TODO Auto-generated constructor stub
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#register(java.lang.String,
	 * java.lang.String, java.lang.String, java.lang.String, java.lang.String,
	 * java.sql.Date, java.lang.String)
	 */
	@Override
	public void register(String username, String password, String email,
			String name, String surname, Date birth, String address)
			throws DuplicatedUsernameException {
		List<User> result = new LinkedList<User>();
		Query q = em.createQuery("FROM User u WHERE u.username=:username");
		q.setParameter("username", username);
		List<?> res = q.getResultList();
		for (Object obj : res) {
			result.add((User) obj);
		}
		if (result.isEmpty()) {
			User user = new User();
			user.setUsername(username);
			user.setPassword(password);
			user.setEmail(email);
			user.setName(name);
			user.setSurname(surname);
			user.setBirth(birth);
			user.setAddress(address);
			em.persist(user);
			// em.flush();
			return;
		}
		throw new DuplicatedUsernameException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#adminAuthenticate(java.lang.String,
	 * java.lang.String)
	 */
	public void adminAuthenticate(String username, String password)
			throws AdminAuthenticationException {
		List<Admin> result = new LinkedList<Admin>();
		Query q = em
				.createQuery("FROM Admin a WHERE a.username=:username AND a.password=:password");
		q.setParameter("username", username);
		q.setParameter("password", password);
		List<?> res = q.getResultList();
		for (Object obj : res) {
			result.add((Admin) obj);
		}
		if (!result.isEmpty()) {
			return;
		}
		throw new AdminAuthenticationException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#login(java.lang.String, java.lang.String)
	 */
	@Override
	public void authenticate(String username, String password)
			throws AuthenticationException {
		List<User> result = new LinkedList<User>();
		Query q = em
				.createQuery("FROM User u WHERE u.username=:username AND u.password=:password");
		q.setParameter("username", username);
		q.setParameter("password", password);
		List<?> res = q.getResultList();
		for (Object obj : res) {
			result.add((User) obj);
		}
		if (!result.isEmpty()) {
			return;
		}
		throw new AuthenticationException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#searchUser(java.lang.String,
	 * java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public List<User> search(String username, String name, String surname,
			String address) {
		List<User> result = new LinkedList<User>();
		Query q = em
				.createQuery("FROM User u WHERE u.username=:username OR u.name=:name OR u.surname=:surname OR u.address=:address");
		q.setParameter("username", username);
		q.setParameter("name", name);
		q.setParameter("surname", surname);
		q.setParameter("address", address);
		List<?> res = q.getResultList();
		for (Object obj : res) {
			result.add((User) obj);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#edit(java.lang.String, java.lang.String,
	 * java.lang.String, java.lang.String, java.lang.String, java.sql.Date,
	 * java.lang.String)
	 */
	@Override
	public void edit(String username, String password, String email,
			String name, String surname, Date birth, String address) {
		Query q = em.createQuery("FROM User u WHERE u.username=:username");
		q.setParameter("username", username);
		User user = (User) q.getSingleResult();
		user.setPassword(password);
		user.setEmail(email);
		user.setName(name);
		user.setSurname(surname);
		user.setBirth(birth);
		user.setAddress(address);
		em.merge(user);
		// em.flush();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#fetch(java.lang.String)
	 */
	@Override
	public User fetch(String username) {
		Query q = em.createQuery("FROM User u WHERE u.username=:username");
		q.setParameter("username", username);
		User user = (User) q.getSingleResult();
		return user;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#fetchAdmin(java.lang.String)
	 */
	public Admin fetchAdmin(String username) {
		Query q = em.createQuery("FROM Admin a WHERE a.username=:username");
		q.setParameter("username", username);
		Admin admin = (Admin) q.getSingleResult();
		return admin;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#fetchDeclaredSkills(java.lang.String)
	 */
	public List<Skill> fetchDeclaredSkills(String username) {
		List<Skill> result = new LinkedList<Skill>();
		Query q = em
				.createQuery("FROM Skill s WHERE s.name in (SELECT h.skill.name FROM Has h WHERE h.user.username=:username)");
		q.setParameter("username", username);
		List<?> res = q.getResultList();
		for (Object obj : res) {
			result.add((Skill) obj);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#removeAllDeclaredSkills(java.lang.String)
	 */
	@Override
	public void removeAllDeclaredSkills(String username) {
		List<Has> result = new LinkedList<Has>();
		Query q1 = em.createQuery("FROM Has h WHERE h.user.username=:username");
		q1.setParameter("username", username);
		List<?> res = q1.getResultList();
		for (Object obj : res) {
			result.add((Has) obj);
		}
		for (Has h : result) {
			int id = h.getId();
			Query q = em.createQuery("DELETE FROM Has h WHERE h.id=:id");
			q.setParameter("id", id);
			q.executeUpdate();
			// em.flush();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see sessions.UserManagerRemote#declareSkill(entities.User,
	 * entities.Skill)
	 */
	@Override
	public void declareSkill(User user, Skill skill) {
		String username = user.getUsername();
		String name = skill.getName();
		List<Has> result = new LinkedList<Has>();
		Query q = em
				.createQuery("FROM Has h WHERE h.user.username=:username AND h.skill.name=:name");
		q.setParameter("username", username);
		q.setParameter("name", name);
		List<?> res = q.getResultList();
		for (Object obj : res) {
			result.add((Has) obj);
		}
		if (result.isEmpty()) {
			Has has = new Has();
			has.setUser(user);
			has.setSkill(skill);
			em.persist(has);
			// em.flush();
		}
	}

}
